home *** CD-ROM | disk | FTP | other *** search
/ CDUTIL 13 / CDUTIL #13 Julio 1995.iso / windows / acadcom / acrx / sample / mountain.cc < prev    next >
Encoding:
Text File  |  1995-02-08  |  42.5 KB  |  1,304 lines

  1. /* Next available MSG number is  34 */
  2.  
  3. /***************************************************************************
  4.    Module Name:  mountain.cc
  5.  
  6.    Copyright (C) 1992, 1993, 1994 by Autodesk, Inc.
  7.  
  8.    Permission to use, copy, modify, and distribute this software in 
  9.    object code form for any purpose and without fee is hereby granted, 
  10.    provided that the above copyright notice appears in all copies and 
  11.    that both that copyright notice and the limited warranty and 
  12.    restricted rights notice below appear in all supporting 
  13.    documentation.
  14.  
  15.    AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.  
  16.    AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 
  17.    MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
  18.    DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 
  19.    UNINTERRUPTED OR ERROR FREE.
  20.  
  21.    Use, duplication, or disclosure by the U.S. Government is subject to 
  22.    restrictions set forth in FAR 52.227-19 (Commercial Computer 
  23.    Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 
  24.    (Rights in Technical Data and Computer Software), as applicable.
  25.     
  26.    .
  27.  
  28.       DESCRIPTION:
  29.  
  30.         RXADS fractal mountain landscape generator
  31.  
  32.         This  program generates fractal mountain landscapes by Fourier
  33.         filtering of random data.  The landscapes are  represented  as
  34.         pface  meshes  within  an  AutoCAD  drawing.   To  run the
  35.         program, first load the RXADS application with the command:
  36.  
  37.             (rxload "mountain")
  38.  
  39.         and enter the command:
  40.  
  41.             MOUNTAIN
  42.  
  43.         You're  asked the to specify the parameters of the mountain as
  44.         follows:
  45.  
  46.             Mesh size (power of 2) <32>:
  47.             Fractal dimension (typically between 1 and 3) <2.15>:
  48.             Power law scaling exponent <1>:
  49.  
  50.         The  mountain  range is  modeled as a square  pface  mesh with
  51.         edge size given by the first prompt.  The mesh size must be  a
  52.         power  of  two (this limitation is imposed by the fast Fourier
  53.         transform algorithm; if you specify a mesh size that's  not  a
  54.         power  of two it will be rounded up to the next larger power).
  55.  
  56.         The  fractal dimension controls the roughness of the generated
  57.         landscape by applying a low-pass spatial filter to the  random
  58.         frequency  domain  data  before performing the inverse Fourier
  59.         transform.  The higher the fractal dimension the  rougher  the
  60.         terrain;  values  between  2  and  3  are typical.  Dimensions
  61.         between 1.7 and  2  generate  Appalachian-type  hills;  values
  62.         between  2 and 2.5 yield Sierra Nevada like peaks; and numbers
  63.         close to 3 result in fantasy landscapes of spires (which  look
  64.         good only at high mesh densities).
  65.  
  66.         The output of the mountain generation algorithm is a table  of
  67.         heights.   Negative  heights  are  set to zero and coloured as
  68.         water.  You can scale elevations above sea  level  by  raising
  69.         the  raw  values to a power specified by the power law scaling
  70.         exponent.  The default value of 1 simply uses  the  elevations
  71.         as generated.  Powers of less than 1 mimic eroded terrain (try
  72.         0.33--cube root scaling often produces  landscapes  that  look
  73.         glacially sculpted like Yosemite).  Powers greater than 1 make
  74.         increasingly forbidding peaks.  Again, if you use large  power
  75.         law  exponents,  the  results  will  look  best at higher mesh
  76.         densities.
  77.  
  78.         Every time  you  enter  the  MOUNTAIN  command  you'll  get  a
  79.         different  landscape.   The random number generator is started
  80.         from the time and date, so a given result will normally  never
  81.         recur.   If  you  use  the  command several times, remember to
  82.         ERASE the previous mesh to keep the new mountains  from  being
  83.         drawn  over  top of the old ones.  If you want to generate the
  84.         same terrain repeatedly (for example, to experiment  with  the
  85.         effects of fractal dimension and power law exponent settings),
  86.         you can set the random sequence used to generate  the  terrain
  87.         with the SEED command.  This command prompts:
  88.  
  89.             Random number seed (0 to reseed) <0xNNNN>:
  90.  
  91.         where  0xNNNN is the current starting seed in hexadecimal.  If
  92.         you enter a nonzero value it is used as the seed by  the  next
  93.         MOUNTAIN  command.   Subsequent commands advance the generator
  94.         and continue  to  generate  different  terrain,  so  you  must
  95.         re-enter  the SEED before each MOUNTAIN command if you want to
  96.         repeat the last output.  The default for the SEED  command  is
  97.         the  last seed entered, so simply entering a blank response to
  98.         the command resets the seed to the last value, making it  easy
  99.         to  repeatedly generate from the same seed.  If a seed of 0 is
  100.         entered, a new random value is generated  from  the  time  and
  101.         date.
  102.  
  103.         The  faces  of  the pface mesh  are  coloured  individually to
  104.         represent their elevation.  The WORLD command  allows  you  to
  105.         choose  between  two  different  colour  schemes.  The command
  106.         prompts you:
  107.  
  108.                 World:  0 = Landscape (8 colours)
  109.                         1 = Landscape (256 colours)
  110.                         2 = Clouds
  111.                 World type <0>:
  112.  
  113.         The default world, 0, colours negative elevations as different
  114.         shades of blue (to indicate "water depth"), and terrain  on  a
  115.         scale  from  green through yellows to white for "snowy peaks".
  116.         World type 1 restricts the palette of colours to  the  default
  117.         AutoCAD  8  colour  set;  the  resulting  pictures  are not as
  118.         attractive but will display properly on systems with 8  colour
  119.         capability   or  above.   World  type  2  selects  colours  to
  120.         illustrate affinity between fractal clouds and mountains.  All
  121.         negative  elevations  in  the  clouds world are coloured blue;
  122.         other faces are assigned shades from dark grey to  white  with
  123.         increasing  elevation.   Pictures  generated  with  the clouds
  124.         colouring are  intended  to  be  viewed  in  plan  view,  from
  125.         directly  above,  and  look  best in shaded renderings at high
  126.         resolution.  Cloud colouring requires a  256  colour  display.
  127.  
  128.         The  mountains are generated on a dark grey (cyan for 8 colour
  129.         landscapes) base, drawn with invisible edges, which serves  to
  130.         obscure the underside of the terrain in hidden line and shaded
  131.         renderings.
  132.  
  133.         The  MOUNTAIN  command  always  generates  a pface  mesh; this
  134.         mesh  can  be  created  either  by  invocation  of  the  PFACE
  135.         command  through  the  ads_command() facility or directly with
  136.         ads_entmake().  The MAKEMODE command lets you specify how  the
  137.         mesh  is  to  be created, allowing you to try both methods and
  138.         compare their relative performance.  You're prompted:
  139.  
  140.                 Mesh generation:  0 = Directly with ads_entmake()
  141.                                   1 = PFACE command via ads_command()
  142.                 Generation type <0>:
  143.  
  144.         Enter  the  generation  mode  you prefer.  Subsequent MOUNTAIN
  145.         commands will  use  the  mode  you  chose.   If  the  mesh  is
  146.         generated with ads_entmake(), extended entity data is attached
  147.         to it that records the  world  type,  fractal  dimension,  and
  148.         power factor used to create the mesh.
  149.  
  150.         References:
  151.  
  152.             Peitgen, H.-O., and Saupe, D. eds., The Science Of Fractal
  153.                 Images, New York: Springer Verlag, 1988.
  154.  
  155.             Press, W. H., Flannery, B. P., Teukolsky, S. A., Vetterling,
  156.                 W. T., Numerical Recipes In C, New Rochelle; Cambridge
  157.                 University Press, 1988.
  158.  
  159.         This Arx application is a conversion from the original sample 
  160.         ADS app mountain.c.
  161.  
  162.         CREATED BY: John Walker November of 1989
  163.         Modification history:
  164.         January 1994, Bill Howison: Converted to an RXADS app.
  165.         March 1994, Thuan Ewe: Reenable ads_command mode.
  166.  
  167.         Function Entry Points:
  168.           AcRx::AppRetCode
  169.             acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt);
  170.  
  171. ***************************************************************************/
  172.  
  173. /**************************************************************************/
  174. /*  MODULE NAME  */
  175. /**************************************************************************/
  176. #define    MOUNTAIN
  177.  
  178. /**************************************************************************/
  179. /*  INCLUDES  */
  180. /**************************************************************************/
  181. #include <stdio.h>
  182. #include <stdlib.h>
  183. #include <string.h>
  184. #include <assert.h>
  185. #include <time.h>
  186. #include <math.h>
  187. #include "ol_errno.h"
  188. #include "rxdefs.h"
  189. #include "adslib.h"
  190.  
  191. #ifdef UNIX
  192. #include <memory.h>
  193. #else
  194. #include <malloc.h>
  195. #endif
  196.  
  197.  
  198. /****************************************************************************/
  199. /*  LOCALLY DEFINED ENTRY POINTS INVOKED BY ARX                             */
  200. /****************************************************************************/
  201. extern "C" {
  202. AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt);
  203.  
  204. }
  205.  
  206. /****************************************************************************/
  207. /*  DEFINES  */
  208. /****************************************************************************/
  209.  
  210. #define AppName  /*MSG1*/"AUTODESK_FRACTAL_MOUNTAINS"
  211.  
  212. #ifndef M_PI
  213. #define M_PI    3.14159265358979323846
  214. #endif
  215.  
  216. #if defined(__WATCOMC__) || defined(TURBOC) || defined(max) || defined(min)
  217. #undef max
  218. #undef min
  219. #endif
  220.  
  221. #define max(a,b) ((a) >  (b) ? (a) : (b))
  222. #define min(a,b) ((a) <= (b) ? (a) : (b))
  223.  
  224. /* Definitions used to address real and imaginary parts in a two-dimensional
  225.    array of complex numbers as stored by fourn(). */
  226.  
  227. #define Real(v, x, y)  v[1 + (((x) * n) + (y)) * 2]
  228. #define Imag(v, x, y)  v[2 + (((x) * n) + (y)) * 2]
  229.  
  230. /*  Data types  */
  231.  
  232. typedef enum {False = 0, True = 1} Boolean;
  233.  
  234. /* Definitions  to  wrap  around  submission  of  AutoCAD commands to
  235.    prevent their being echoed.  */
  236.  
  237. #define Cmdecho  False                /* Make True for debug command output */
  238.  
  239. #define CommandB()  { struct resbuf rBc, rBb, rBu, rBh; \
  240.         ads_getvar(/*MSG0*/"CMDECHO", &rBc); \
  241.         ads_getvar(/*MSG0*/"BLIPMODE", &rBb); \
  242.         ads_getvar(/*MSG0*/"HIGHLIGHT", &rBh); \
  243.         rBu.restype = RTSHORT; \
  244.         rBu.resval.rint = (int) Cmdecho; \
  245.         ads_setvar(/*MSG0*/"CMDECHO", &rBu); \
  246.         rBu.resval.rint = (int) False; \
  247.         ads_setvar(/*MSG0*/"BLIPMODE", &rBu); \
  248.         ads_setvar(/*MSG0*/"HIGHLIGHT", &rBu)
  249.  
  250. #define CommandE()  ads_setvar(/*MSG0*/"CMDECHO", &rBc); \
  251.                     ads_setvar(/*MSG0*/"BLIPMODE", &rBb); \
  252.                     ads_setvar(/*MSG0*/"HIGHLIGHT", &rBh); }
  253.  
  254. /*  Definitions  that permit you to push and pop system variables with
  255.     minimal complexity.  These don't work  (and  will  cause  horrible
  256.     crashes  if  used)  with  string  variables,  but since all string
  257.     variables are read-only, they cannot be saved and restored in  any
  258.     case.  */
  259.  
  260. #define PushVar(var, cell, newval, newtype) { struct resbuf cell, cNeW; \
  261.         ads_getvar(var, &cell); cNeW.restype = cell.restype;             \
  262.         cNeW.resval.newtype = newval; ads_setvar(var, &cNeW)
  263.  
  264. #define PopVar(var, cell) ads_setvar(var, &cell); }
  265.  
  266. /* Set point variable from three co-ordinates */
  267.  
  268. #define Spoint(pt, x, y, z)  pt[X] = (x);  pt[Y] = (y);  pt[Z] = (z)
  269.  
  270. /* Copy point from another */
  271.  
  272. #define Cpoint(d, s)   d[X] = s[X];  d[Y] = s[Y];  d[Z] = s[Z]
  273.  
  274. /* Definitions for building result buffer chains. */
  275.  
  276. #define tacky()     struct resbuf *rb, *rbtail, *ri
  277. #define tackrb(t)   ri=ads_newrb(t);  rbtail->rbnext=ri;  rbtail=ri
  278. #define defent(e)   rb=ri=rbtail=ads_newrb(0); ri->resval.rstring = strsave(e)
  279. #define Xed(g)     (1000 + (g))       /* Generate extended entity data code */
  280. #define makent() { int stat=ads_entmake(rb); if (stat!=RTNORM) { \
  281.                    ads_printf(/*MSG2*/"Error creating %s entity\n",       \
  282.                    rb->resval.rstring); } /*ads_relrb(rb);*/ }
  283. #define tackint(code, val) tackrb(code); ri->resval.rint = (val)
  284. #define tackreal(code, val) tackrb(code); ri->resval.rreal = (val)
  285. #define tackpoint(code, x, y, z) tackrb(code); \
  286.         Spoint(ri->resval.rpoint, (x), (y), (z))
  287. #define tackvec(code, vec) tackrb(code); Cpoint(ri->resval.rpoint, vec)
  288. #define tackstring(code, s) tackrb(code), ri->resval.rstring = strsave(s)
  289.  
  290. #define V  (void)
  291.  
  292. /* Utility definition to get an  array's  element  count  (at  compile
  293.    time).   For  example:
  294.  
  295.        int  arr[] = {1,2,3,4,5};
  296.        ...
  297.        printf("%d", ELEMENTS(arr));
  298.  
  299.    would print a five.  ELEMENTS("abc") can also be used to  tell  how
  300.    many  bytes are in a string constant INCLUDING THE TRAILING NULL. */
  301.  
  302. #define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
  303.  
  304. /*  Display parameters  */
  305.  
  306. #define COL_BASE    (wtype == 0 ? 4 : 250) /* Baseplate colour */
  307. #define BASE_THICK  0.1               /* Baseplate thickness */
  308.  
  309. /****************************************************************************/
  310. /*  LOCAL FUNCTION FORWARD DECLARATIONS  */
  311. /****************************************************************************/
  312. extern "C" {
  313. long    time _((long *));
  314. static void    fourn _((float *, int *, int, int));
  315. static void    initgauss _((int));
  316. static double  gauss _((void));
  317. static void    spectralsynth _((float **, int, double));
  318. static void    mtn_srand _((unsigned int));
  319. static int     mtn_rand _((void));
  320. static int     veryrandom _((void));
  321. static Boolean funcload _((void));
  322. static int     funcunload _((void));
  323. static int     dofun _((void));
  324. static Boolean initacad _((Boolean));
  325. static void    initseed _((void));
  326. static int     calccol _((float *, int, int, int, ads_real, ads_real));
  327. static void    meshcol _((float *, int, int, int, ads_real, ads_real));
  328. static void    genmesh _((float *, int, ads_real, ads_real));
  329. static char    *strsave _((char *));
  330. static void    makevtx _((ads_point));
  331. static void    makeface _((int, int, int, int, int));
  332. static void    makemesh _((float *, int, ads_real, ads_real));
  333. static void    mountain _((void));
  334. static void    seed _((void));
  335. static void    world _((void));
  336. static void    makemode _((void));
  337.  
  338. #ifdef DEBUG
  339. void    test _((void));
  340. #endif
  341. }
  342. /**************************************************************************/
  343. /*  GLOBAL VARIABLES  */
  344. /**************************************************************************/
  345.  
  346. static int nrand;                     /* Gauss() sample count */
  347. static double arand, gaussadd, gaussfac; /* Gaussian random parameters */
  348. static int rseed;                     /* Current random seed */
  349. static Boolean seeded = False;        /* Initial seed computed ? */
  350. static Boolean forceseed = False;     /* Force seed on next computation ? */
  351. static int ccolour = -1;              /* Current face colour */
  352. static ads_real fracdim = 2.15;       /* Fractal dimension */
  353. static ads_real powscale = 1.0;       /* Elevation power factor */
  354. static int wtype = 0;                 /* World type */
  355. static Boolean entmake = True;        /* Use ads_entmake() to create mesh ? */
  356.  
  357. /* The following variables are used by the psuedo-random sequence generator
  358.    veryrandom() and must be unsigned so the right shift works properly */
  359.  
  360. static unsigned long regA = 1;
  361. static unsigned long regB = 1;
  362. static unsigned long regC = 1;
  363.  
  364. /*  Command definition and dispatch table.  */
  365.  
  366. struct {
  367.         char *cmdname;
  368.         void (*cmdfunc)();
  369. } cmdtab[] = {
  370. /*        Name         Function  */
  371. #ifdef DEBUG
  372. {/*MSG3*/"TEST",       test},
  373. #endif
  374. {/*MSG4*/"MAKEMODE",   makemode},
  375. {/*MSG5*/"MOUNTAIN",   mountain},
  376. {/*MSG6*/"SEED",       seed},
  377. {/*MSG7*/"WORLD",      world}
  378. };
  379.  
  380. /*      FOURN  --  Multi-dimensional fast Fourier transform
  381.  
  382.         Called with arguments:
  383.  
  384.            data       A  one-dimensional  array  of  floats  (NOTE!!!   NOT
  385.                       DOUBLES!!), indexed from one (NOTE!!!   NOT  ZERO!!),
  386.                       containing  pairs of numbers representing the complex
  387.                       valued samples.  The Fourier transformed results  are
  388.                       returned in the same array.
  389.  
  390.            nn         An  array specifying the edge size in each dimension.
  391.                       THIS ARRAY IS INDEXED FROM  ONE,  AND  ALL  THE  EDGE
  392.                       SIZES MUST BE POWERS OF TWO!!!
  393.  
  394.            ndim       Number of dimensions of FFT to perform.  Set to 2 for
  395.                       two dimensional FFT.
  396.  
  397.            isign      If 1, a Fourier transform is done, if -1 the  inverse
  398.                       transformation is performed.
  399.  
  400.         This  function  is essentially as given in Press et al., "Numerical
  401.         Recipes In C", Section 12.11, pp.  467-470.
  402. */
  403.  
  404. static void fourn(float *data, int *nn, int ndim, int isign)
  405. {
  406.     register int i1, i2, i3;
  407.     int i2rev, i3rev, ip1, ip2, ip3, ifp1, ifp2;
  408.     int ibit, idim, k1, k2, n, nprev, nrem, ntot;
  409.     float tempi, tempr;
  410.     double theta, wi, wpi, wpr, wr, wtemp;
  411.  
  412. #define SWAP(a,b) tempr=(a); (a) = (b); (b) = tempr
  413.  
  414.     ntot = 1;
  415.     for (idim = 1; idim <= ndim; idim++)
  416.         ntot *= nn[idim];
  417.     nprev = 1;
  418.     for (idim = ndim; idim >= 1; idim--) {
  419.         n = nn[idim];
  420.         nrem = ntot / (n * nprev);
  421.         ip1 = nprev << 1;
  422.         ip2 = ip1 * n;
  423.         ip3 = ip2 * nrem;
  424.         i2rev = 1;
  425.         for (i2 = 1; i2 <= ip2; i2 += ip1) {
  426.             if (i2 < i2rev) {
  427.                 for (i1 = i2; i1 <= i2 + ip1 - 2; i1 += 2) {
  428.                     for (i3 = i1; i3 <= ip3; i3 += ip2) {
  429.                         i3rev = i2rev + i3 - i2;
  430.                         SWAP(data[i3], data[i3rev]);
  431.                         SWAP(data[i3 + 1], data[i3rev + 1]);
  432.                     }
  433.                 }
  434.             }
  435.             ibit = ip2 >> 1;
  436.             while (ibit >= ip1 && i2rev > ibit) {
  437.                 i2rev -= ibit;
  438.                 ibit >>= 1;
  439.             }
  440.             i2rev += ibit;
  441.         }
  442.         ifp1 = ip1;
  443.         while (ifp1 < ip2) {
  444.             ifp2 = ifp1 << 1;
  445.             theta = isign * 6.28318530717959 / (ifp2 / ip1);
  446.             wtemp = sin(0.5 * theta);
  447.             wpr = -2.0 * wtemp * wtemp;
  448.             wpi = sin(theta);
  449.             wr = 1.0;
  450.             wi = 0.0;
  451.             for (i3 = 1; i3 <= ifp1; i3 += ip1) {
  452.                 for (i1 = i3; i1 <= i3 + ip1 - 2; i1 += 2) {
  453.                     for (i2 = i1; i2 <= ip3; i2 += ifp2) {
  454.                         k1 = i2;
  455.                         k2 = k1 + ifp1;
  456.                         tempr = wr * data[k2] - wi * data[k2 + 1];
  457.                         tempi = wr * data[k2 + 1] + wi * data[k2];
  458.                         data[k2] = data[k1] - tempr;
  459.                         data[k2 + 1] = data[k1 + 1] - tempi;
  460.                         data[k1] += tempr;
  461.                         data[k1 + 1] += tempi;
  462.                     }
  463.                 }
  464.                 wr = (wtemp = wr) * wpr - wi * wpi + wr;
  465.                 wi = wi * wpr + wtemp * wpi + wi;
  466.             }
  467.             ifp1 = ifp2;
  468.         }
  469.         nprev *= n;
  470.     }
  471. }
  472. #undef SWAP
  473.  
  474. /*  INITGAUSS  --  Initialise random number generators.  */
  475.  
  476. static void initgauss(int seed)
  477. {
  478.     nrand = 4;
  479.     arand = pow(2.0, (sizeof(int) * 8) - 1.0) - 1.0;
  480.     gaussadd = sqrt(3.0 * nrand);
  481.     gaussfac = 2 * gaussadd / (nrand * arand);
  482.     mtn_srand(seed);
  483. }
  484.  
  485. /*  GAUSS  --  Return a Gaussian random number.  */
  486.  
  487. static double gauss()
  488. {
  489.     int i;
  490.     double sum = 0.0;
  491.  
  492.     for (i = 1; i <= nrand; i++) {
  493.         sum += mtn_rand();
  494.     }
  495.     return gaussfac * sum - gaussadd;
  496. }
  497.  
  498. /*  SPECTRALSYNTH  --  Spectrally synthesised fractal motion in two
  499.                        dimensions.  */
  500.  
  501. static void spectralsynth(float **x, int n, double h)
  502. {
  503.     int i, j, i0, j0, nsize[3];
  504.     double rad, phase;
  505.     float *a;
  506.  
  507.     a = (float *) malloc((unsigned)(i = (((n * n) + 1) * 2 * sizeof(float))));
  508.     if (a == NULL) {
  509.         V fprintf(stderr,
  510.                   /*MSG8*/"Cannot allocate %d x %d result array (%d bytes).\n",
  511.                   n, n, i);
  512.         exit(1);
  513.     }
  514.     *x = a;
  515.     V memset((char *) a, 0, i);       /* Clear array to zeroes */
  516.  
  517.     for (i = 0; i <= n / 2; i++) {
  518.         for (j = 0; j <= n / 2; j++) {
  519.             phase = 2 * M_PI * (mtn_rand() / arand);
  520.             if (i != 0 || j != 0) {
  521.                 rad = pow((double) (i * i + j * j), -(h + 1) / 2) * gauss();
  522.             } else {
  523.                 rad = 0;
  524.             }
  525.             Real(a, i, j) = rad * cos(phase);
  526.             Imag(a, i, j) = rad * sin(phase);
  527.             i0 = (i == 0) ? 0 : n - i;
  528.             j0 = (j == 0) ? 0 : n - j;
  529.             Real(a, i0, j0) = rad * cos(phase);
  530.             Imag(a, i0, j0) = - rad * sin(phase);
  531.         }
  532.     }
  533.     Imag(a, n / 2, 0) = Imag(a, 0, n / 2) = Imag(a, n / 2, n / 2) = 0;
  534.     for (i = 1; i <= n / 2 - 1; i++) {
  535.         for (j = 1; j <= n / 2 - 1; j++) {
  536.             phase = 2 * M_PI * (mtn_rand() / arand);
  537.             rad = pow((double) (i * i + j * j), -(h + 1) / 2) * gauss();
  538.             Real(a, i, n - j) = rad * cos(phase);
  539.             Imag(a, i, n - j) = rad * sin(phase);
  540.             Real(a, n - i, j) = rad * cos(phase);
  541.             Imag(a, n - i, j) = - rad * sin(phase);
  542.         }
  543.     }
  544.  
  545.     nsize[0] = 0;
  546.     nsize[1] = nsize[2] = n;          /* Dimension of frequency domain array */
  547.     fourn(a, nsize, 2, -1);           /* Take inverse 2D Fourier transform */
  548. }
  549.  
  550. /*  MTN_SRAND  --  Seed the psuedo-random number generator.  */
  551.  
  552. static void
  553. /*FCN*/mtn_srand(unsigned int seed)
  554. {
  555.     regA = regB = regC = seed;
  556. }
  557.  
  558. /*  MTN_RAND  --  The psuedo-random number generator.  */
  559.  
  560. static int
  561. /*FCN*/mtn_rand()
  562. {
  563.     int i;
  564.     int rnum = 0;
  565.  
  566.     for (i=0; i < sizeof(int)*8; i++) {
  567.         rnum |= veryrandom();
  568.         rnum <<= 1;
  569.     }
  570.     return rnum;
  571. }
  572.  
  573. /*  VERYRANDOM  --  Psuedo-Random Sequence Generator for 32-Bit CPUs,
  574.                     by Bruce Schneier, Dr. Dobb's Journal, February 1992 */
  575.  
  576. static int
  577. /*FCN*/veryrandom()
  578. {
  579.     /* regA is a 32-bit Linear Feedback Shift Register (LFSR) */
  580.     /* regB is a 31-bit LFSR.  regC is a 29-bit LFSR. */
  581.     /* The feedback sequences are chosen to be maximum length. */
  582.     regA = ((((regA>>31)^(regA>>6)^(regA>>4)^(regA>>2)^(regA>>1)^regA)
  583.         & 0x00000001)<<31) | (regA>>1);
  584.     regB = ((((regB>>30)^(regB>>2)) & 0x00000001)<<30) | (regB>>1);
  585.     regC = ((((regC>>28)^(regC>>1)) & 0x00000001)<<28) | (regC>>1);
  586.     return ((regA & regB) | (!regA & regC)) & 0x00000001;
  587. }
  588.  
  589. /*  INITACAD  --  Initialise the required modes in the AutoCAD
  590.                   drawing.  */
  591.  
  592. static Boolean initacad(Boolean reset)
  593. {
  594.     static Boolean initdone, initok;
  595.  
  596.     if (reset) {
  597.         initdone = False;
  598.         initok = True;
  599.     } else {
  600.         if (!initdone) {
  601.             struct resbuf *rp;
  602.             static char aname[] = AppName;  /* Static to keep compiler from
  603.                                                making making one copy of
  604.                                                constant string for every
  605.                                                reference below. */
  606.  
  607.             /* First of all, see if our application is registered
  608.                and register it if not. */
  609.  
  610.             if ((rp = ads_tblsearch(/*MSG0*/"APPID", aname, False)) == NULL) {
  611.                 if (ads_regapp(aname) != RTNORM) {
  612.                     ads_printf(/*MSG11*/"Cannot register application %s.\n",
  613.                                aname);
  614.                     initdone = True;
  615.                     return (initok = False);
  616.                 }
  617.             } else {
  618.                 ads_relrb(rp);
  619.             }
  620.  
  621.             /* Reset the program modes to standard values upon
  622.                entry to the drawing editor. */
  623.  
  624.             initdone = initok = True;
  625.  
  626.             seeded = False;           /* No seed specified */
  627.             forceseed = False;        /* No seed stuck in its throat */
  628.             fracdim = 2.15;           /* Fractal dimension */
  629.             powscale = 1.0;           /* Elevation power factor */
  630.             wtype = 0;                /* World type */
  631.             entmake = True;           /* Use ads_entmake to create meshes */
  632.         }
  633.     }
  634.     return initok;
  635. }
  636.  
  637. /******************************************************************************//*.doc funcload(internal) */
  638. /*+
  639.     This function is called to define all function names in the RXADS
  640.     function table.  Each named function will be callable from lisp or
  641.     invokable from another ADS or RXADS application.
  642. -*/
  643. /******************************************************************************/
  644. static Boolean funcload()
  645. {
  646.     char ccbuf[40];
  647.     int i;
  648.  
  649.     V strcpy(ccbuf, /*MSG0*/"C:");
  650.     for (i = 0; i < ELEMENTS(cmdtab); i++) {
  651.         V strcpy(ccbuf + 2, cmdtab[i].cmdname);
  652.         ads_defun(ccbuf, i);
  653.     }
  654.  
  655.     return initacad(True);            /* Reset AutoCAD initialisation */
  656. }
  657.  
  658. /******************************************************************************//*.doc funclunoad(internal) */
  659. /*+
  660.     This function is called to undefine all function names in the RXADS
  661.     function table.  Each named function will be removed from the
  662.     AutoLISP hash table.
  663. -*/
  664. /******************************************************************************/
  665. static int
  666. /*FCN*/funcunload()
  667. {
  668.     char ccbuf[40];
  669.     int i;
  670.  
  671.     /* Undefine each function we defined */
  672.  
  673.     V strcpy(ccbuf, /*MSG0*/"C:");
  674.     for (i = 0; i < ELEMENTS(cmdtab); i++) {
  675.         V strcpy(ccbuf + 2, cmdtab[i].cmdname);
  676.         ads_undef(ccbuf, i);
  677.     }
  678.  
  679.     return RTNORM;
  680. }
  681.  
  682. /******************************************************************************/
  683. /*.doc dofun(internal) */
  684. /*+
  685.     This function is called to invoke the function which has the
  686.     registerd function code that is obtained from  ads_getfuncode.  The
  687.     function will return RTERROR if the function code is invalid, or
  688.     RSERR if the invoked function fails to return RTNORM.  The value
  689.     RSRSLT will be returned if the function code is valid and the
  690.     invoked subroutine returns RTNORM.
  691. -*/
  692. /******************************************************************************/
  693. static int
  694. /*FCN*/dofun()
  695. {
  696.     int    cindex;
  697.  
  698.     ads_retvoid();
  699.        
  700.     if (!initacad(False)) {
  701.         ads_printf(/*MSG10*/"\nUnable to initialise application.\n");
  702.     } else {
  703.         if ((cindex = ads_getfuncode()) < 0 || cindex > ELEMENTS(cmdtab))
  704.             return RTERROR;
  705.  
  706.         (*cmdtab[cindex].cmdfunc)();
  707.         return RSRSLT;
  708.     }
  709.     return RTERROR;
  710. }
  711.  
  712. #ifdef DEBUG
  713. /*  TEST  --  Verify that command invocation works.  */
  714.  
  715. static void test()
  716. {
  717.     ads_printf(/*MSG12*/"\nTEST command!\n");
  718. #ifdef DEBUGDUMP
  719.     {   ads_name en;
  720.         struct resbuf *rb, *ri;
  721.  
  722.         ads_entnext(NULL, en);
  723.         rb = ri = ads_entget(en);
  724.  
  725.         while (ri != NULL) {
  726.             ads_printf(/*MSG13*/"Type %d\n", ri->restype);
  727.             ri = ri->rbnext;
  728.         }
  729.         ads_relrb(rb);
  730.     }
  731. #else
  732.     sleep(30);                        /* Delay to let debugger snag us */
  733. #endif
  734. }
  735. #endif
  736.  
  737. /*  INITSEED  --  Generate initial random seed, if needed.  */
  738.  
  739. static void initseed()
  740. {
  741.     if (!seeded) {
  742.         int i;
  743.  
  744.         mtn_srand(((int) (time((long *) NULL) ^ 0x5B3CF37C) & ((int) ~0)));
  745.         for (i = 0; i < 7; i++)
  746.             V mtn_rand();
  747.         rseed = mtn_rand();
  748.         seeded = forceseed = True;
  749.     }
  750. }
  751.  
  752. /*  CALCCOL  --  Calculate colour of mesh item from its relative
  753.                  elevation.  */
  754.  
  755. static int calccol(float *a, int n, int x, int y, ads_real rmax, ads_real rmin)
  756. {
  757.     ads_real h1 = Real(a, x, y),
  758.              h2 = Real(a, x + 1, y),
  759.              h3 = Real(a, x, y + 1),
  760.              h4 = Real(a, x + 1, y + 1),
  761.              h;
  762.     int rcol;
  763.  
  764.     static struct {
  765.        ads_real cthresh;
  766.        int tcolour;
  767.     } ctab[] = {
  768.        {0.25, 80},
  769.        {0.6, 90},
  770.        {0.75, 50},
  771.        {0.80, 40},
  772.        {0.90, 131},
  773.        {1.00, 255}
  774.       },
  775.       etab[] = {
  776.        {0.50, 3},
  777.        {0.60, 2},
  778.        {0.80, 1},
  779.        {0.90, 6},
  780.        {1.00, 7}
  781.       },
  782.       clouds[] = {
  783.        {0.1666, 250},
  784.        {0.3333, 251},
  785.        {0.5000, 252},
  786.        {0.6666, 253},
  787.        {0.8333, 254},
  788.        {1.0000, 255}
  789.       };
  790.  
  791.     h = max(h1, max(h2, max(h3, h4)));
  792.     if (h <= 0) {
  793.         int ih;
  794.  
  795.         if (wtype == 0 || wtype == 2) {
  796.             rcol = 5;                 /* Flat blue */
  797.         } else {
  798.             h = (h1 + h2 + h3 + h4) / 4;
  799.             if (rmin == 0)
  800.                 rmin = 1;
  801.             h = h / rmin;
  802.             ih = (int)((h * 3) + 0.5);
  803.             rcol = 140 + min(3, ih) * 10;
  804.         }
  805.     } else {
  806.         int i;
  807.  
  808.         if (rmax == 0)
  809.             rmax = 1;
  810.         h = h / rmax;
  811.         if (wtype == 0) {
  812.             for (i = 0; i < ELEMENTS(etab); i++) {
  813.                 if (h <= etab[i].cthresh)
  814.                     break;
  815.             }
  816.             assert(i < ELEMENTS(etab));
  817.             rcol = etab[i].tcolour;
  818.         } else if (wtype == 2) {
  819.             for (i = 0; i < ELEMENTS(clouds); i++) {
  820.                 if (h <= clouds[i].cthresh)
  821.                     break;
  822.             }
  823.             assert(i < ELEMENTS(clouds));
  824.             rcol = clouds[i].tcolour;
  825.         } else {
  826.             for (i = 0; i < ELEMENTS(ctab); i++) {
  827.                 if (h <= ctab[i].cthresh)
  828.                     break;
  829.             }
  830.             assert(i < ELEMENTS(ctab));
  831.             rcol = ctab[i].tcolour;
  832.         }
  833.     }
  834.     return rcol;
  835. }
  836.  
  837. /*  MESHCOL  --  Set colour of mesh item from its relative elevation.  */
  838.  
  839. static void meshcol(float *a, int n, int x, int y, ads_real rmax, ads_real rmin) {
  840.     int rcol = calccol(a, n, x, y, rmax, rmin);
  841.  
  842.     if (ccolour != rcol) {
  843.         ccolour = rcol;
  844.         ads_command(RTSTR, /*MSG31*/"_color", RTSHORT, ccolour, RTNONE);
  845.     }
  846. }
  847.  
  848. /*  GENMESH  --  Generate mesh from elevation array.  This version
  849.                  creates the mesh by submitting a PFACE command
  850.                  with the ads_command function.  */
  851.  
  852. static void genmesh(float *a, int n, ads_real rmax, ads_real rmin) {
  853.     int i, j;
  854.  
  855.     CommandB();
  856.     ads_command(RTSTR, /*MSG32*/"_.Pface", RTNONE);
  857.  
  858.     /* Send the vertex table. */
  859.  
  860.     for (i = 0; i < n; i++) {
  861.         for (j = 0; j < n; j++) {
  862.             ads_point p;
  863.  
  864.             Spoint(p, i, j,
  865.                    BASE_THICK + (n / (rmax * 2)) * max(0, Real(a, i, j)));
  866.             ads_command(RT3DPOINT, p, RTNONE);
  867.         }
  868.     }
  869.  
  870.     /* Send the baseplate vertices.  We compute and store the
  871.        four edges of the baseplate, addressed by edge number from
  872.        0 to 3 and vertex number along the edge. */
  873.  
  874.     for (i = 0; i < n; i++) {
  875.         ads_point p1, p2, p3, p4;
  876.  
  877.         Spoint(p1, i, 0, 0);
  878.         Spoint(p2, i, n - 1, 0);
  879.         Spoint(p3, 0, i, 0);
  880.         Spoint(p4, n - 1, i, 0);
  881.         ads_command(RT3DPOINT, p1, RT3DPOINT, p2,
  882.                     RT3DPOINT, p3, RT3DPOINT, p4, RTNONE);
  883.     }
  884.  
  885.     ads_command(RTSTR, "", RTNONE);
  886.  
  887.     /* Send the mesh tiles. */
  888.  
  889.     ccolour = -1;
  890. #define Vtx(x, y) ((((x) * n) + (y)) + 1)     /* Address mesh vertex */
  891. #define Bpx(e, x) (((n * n) + 1) + (((x) * 4) + (e)))
  892.     for (i = 0; i < (n - 1); i++) {
  893.         for (j = 0; j < (n - 1); j++) {
  894.             meshcol(a, n, i, j, rmax, rmin);
  895.             ads_command(RTSHORT, Vtx(i, j),
  896.                         RTSHORT, Vtx(i, j + 1) * (j == n - 2 ? 1 : -1),
  897.                         RTSHORT, Vtx(i + 1, j + 1) * (i == n - 2 ? 1 : -1),
  898.                         RTSHORT, Vtx(i + 1, j),
  899.                         RTSTR, "", RTNONE);
  900.         }
  901.     }
  902.  
  903.  
  904.     /* Draw the baseplate */
  905.  
  906.     ads_command(RTSTR, /*MSG33*/"_color", RTSHORT, COL_BASE, RTNONE);
  907.     ads_command(RTSHORT, -Bpx(0, 0), RTSHORT, -Bpx(1, 0),
  908.                 RTSHORT, -Bpx(1, n - 1), RTSHORT, -Bpx(0, n - 1),
  909.                 RTSTR, "", RTNONE);
  910.  
  911.     /* Build the "walls" that connect the baseplate to the edges
  912.        of the model. */
  913.  
  914.     for (i = 0; i < n - 1; i++) {
  915.         ads_command(RTSHORT, -Bpx(0, i),
  916.                     RTSHORT, -Vtx(i, 0),
  917.                     RTSHORT, -Vtx(i + 1, 0),
  918.                     RTSHORT, -Bpx(0, i + 1),
  919.                     RTSTR, "",
  920.  
  921.                     RTSHORT, -Bpx(1, i),
  922.                     RTSHORT, -Vtx(i, n - 1),
  923.                     RTSHORT, -Vtx(i + 1, n - 1),
  924.                     RTSHORT, -Bpx(1, i + 1),
  925.                     RTSTR, "",
  926.  
  927.                     RTSHORT, -Bpx(2, i),
  928.                     RTSHORT, -Vtx(0, i),
  929.                     RTSHORT, -Vtx(0, i + 1),
  930.                     RTSHORT, -Bpx(2, i + 1),
  931.                     RTSTR, "",
  932.  
  933.                     RTSHORT, -Bpx(3, i),
  934.                     RTSHORT, -Vtx(n - 1, i),
  935.                     RTSHORT, -Vtx(n - 1, i + 1),
  936.                     RTSHORT, -Bpx(3, i + 1),
  937.                     RTSTR, "", RTNONE);
  938.     }
  939.  
  940. #undef Vtx
  941. #undef Bpx
  942.     ads_command(RTSTR, "", RTNONE);
  943.     CommandE();
  944. }
  945.  
  946.  
  947.  
  948. /*  STRSAVE  --  Allocate a duplicate of a string.  */
  949.  
  950. static char *strsave(char *s)
  951. {
  952.     char *c = (char *)malloc((unsigned) (strlen(s) + 1));
  953.  
  954.     if (c == NULL)
  955.         acrx_abort(/*MSG15*/"Out of memory");
  956.     V strcpy(c, s);
  957.     return c;
  958. }
  959.  
  960. /*  MAKEVTX  --  Append vertex entity to the database. */
  961.  
  962. static void makevtx(ads_point p)
  963. {
  964.     tacky();
  965.  
  966.     defent(/*MSG0*/"VERTEX");
  967.     tackvec(10, p);                   /* Vertex point */
  968.     tackint(70, 128 + 64);            /* Flags = Pface vertex point */
  969.     makent();
  970. }
  971.  
  972. /*  MAKEFACE  --  Append vertex entity representing a face in the mesh. */
  973.  
  974. static void makeface(int colour, int p1, int p2, int p3, int p4)
  975. {
  976.     tacky();
  977.  
  978.     defent(/*MSG0*/"VERTEX");
  979.     tackpoint(10, 0, 0, 0);           /* Vertex point */
  980.     tackint(62, colour);              /* Face colour */
  981.     tackint(70, 128);                 /* Vertex flags = Pface mesh face */
  982.     tackint(71, p1);                  /* Vertex 1 */
  983.     tackint(72, p2);                  /* Vertex 2 */
  984.     tackint(73, p3);                  /* Vertex 3 */
  985.     tackint(74, p4);                  /* Vertex 4 */
  986.     makent();
  987. }
  988.  
  989. /*  MAKEMESH  --  Create the mesh using the ads_entmake mechanism.  */
  990.  
  991. static void makemesh(float *a, int n, ads_real rmax, ads_real rmin)
  992. {
  993.     int i, j;
  994.     tacky();
  995.  
  996.     defent(/*MSG0*/"POLYLINE");
  997.     tackint(66, 1);                   /* Complex entity flag */
  998.     tackint(70, 64);                  /* Polyline type flags: pface mesh */
  999.     tackint(71, n * n + 4 * n);       /* Vertex count = Mesh plus
  1000.                                                         baseplate edges */
  1001.     /*      Total faces = n^2 +                   mesh tiles
  1002.                                 1 +               baseplate
  1003.                                     4 * (n - 1)   wall tiles. */
  1004.     tackint(72, n * n + 1 + 4 * (n - 1));
  1005.  
  1006.     /* Tack on extended entity data that records the generation
  1007.        parameters of the mesh. */
  1008.  
  1009.     tackrb(-3);                       /* Emplace start of application data */
  1010.  
  1011.     tackstring(Xed(1), AppName);      /* Application name */
  1012.     tackint(Xed(70), wtype);          /* World type */
  1013.     tackreal(Xed(40), fracdim);       /* Fractal dimension */
  1014.     tackreal(Xed(40), powscale);      /* Elevation power factor */
  1015.     makent();
  1016.  
  1017.     /* Send the vertex table. */
  1018.  
  1019.     for (i = 0; i < n; i++) {
  1020.         for (j = 0; j < n; j++) {
  1021.             ads_point p;
  1022.  
  1023.             Spoint(p, i, j,
  1024.                    BASE_THICK + (n / (rmax * 2)) * max(0, Real(a, i, j)));
  1025.  
  1026.             makevtx(p);
  1027.         }
  1028.     }
  1029.  
  1030.     /* Send the baseplate vertices.  We compute and store the
  1031.        four edges of the baseplate, addressed by edge number from
  1032.        0 to 3 and vertex number along the edge. */
  1033.  
  1034.     for (i = 0; i < n; i++) {
  1035.         ads_point p;
  1036.  
  1037.         Spoint(p, i, 0, 0);
  1038.         makevtx(p);
  1039.         Spoint(p, i, n - 1, 0);
  1040.         makevtx(p);
  1041.         Spoint(p, 0, i, 0);
  1042.         makevtx(p);
  1043.         Spoint(p, n - 1, i, 0);
  1044.         makevtx(p);
  1045.     }
  1046.  
  1047.     /* Send the mesh tiles. */
  1048.  
  1049. #define Vtx(x, y) ((((x) * n) + (y)) + 1)     /* Address mesh vertex */
  1050. #define Bpx(e, x) (((n * n) + 1) + (((x) * 4) + (e)))
  1051.     for (i = 0; i < (n - 1); i++) {
  1052.         for (j = 0; j < (n - 1); j++) {
  1053.             makeface(calccol(a, n, i, j, rmax, rmin),
  1054.                      Vtx(i, j),
  1055.                      Vtx(i, j + 1) * (j == n - 2 ? 1 : -1),
  1056.                      Vtx(i + 1, j + 1) * (i == n - 2 ? 1 : -1),
  1057.                      Vtx(i + 1, j));
  1058.         }
  1059.     }
  1060.  
  1061.     /* Draw the baseplate */
  1062.  
  1063.     makeface(COL_BASE,  -Bpx(0, 0), -Bpx(1, 0),
  1064.              -Bpx(1, n - 1), -Bpx(0, n - 1));
  1065.  
  1066.     /* Build the "walls" that connect the baseplate to the edges
  1067.        of the model. */
  1068.  
  1069.     for (i = 0; i < n - 1; i++) {
  1070.         makeface(COL_BASE,
  1071.                  -Bpx(0, i),
  1072.                  -Vtx(i, 0),
  1073.                  -Vtx(i + 1, 0),
  1074.                  -Bpx(0, i + 1));
  1075.  
  1076.         makeface(COL_BASE,
  1077.                  -Bpx(1, i),
  1078.                  -Vtx(i, n - 1),
  1079.                  -Vtx(i + 1, n - 1),
  1080.                  -Bpx(1, i + 1));
  1081.  
  1082.         makeface(COL_BASE,
  1083.                  -Bpx(2, i),
  1084.                  -Vtx(0, i),
  1085.                  -Vtx(0, i + 1),
  1086.                  -Bpx(2, i + 1));
  1087.  
  1088.         makeface(COL_BASE,
  1089.                  -Bpx(3, i),
  1090.                  -Vtx(n - 1, i),
  1091.                  -Vtx(n - 1, i + 1),
  1092.                  -Bpx(3, i + 1));
  1093.     }
  1094. #undef Vtx
  1095. #undef Bpx
  1096.  
  1097.     /* Finally, tack on the SEQEND entity that triggers generation
  1098.        of the whole shebang. */
  1099.  
  1100.     defent(/*MSG0*/"SEQEND");
  1101.     makent();
  1102. }
  1103.  
  1104. #undef defent
  1105. #undef tackrb
  1106.  
  1107. /*  MOUNTAIN  --  Make a mountain.  */
  1108.  
  1109. static void mountain()
  1110. {
  1111.     float *a;
  1112.     int i, j, uds;
  1113.     static int n = 32;
  1114.     char tbuf[80];
  1115.     ads_real rmin = 1e50, rmax = -1e50;
  1116.  
  1117.     ads_initget(2 + 4, NULL);
  1118.     V sprintf(tbuf, /*MSG16*/"\nMesh size (power of 2) <%d>: ", n);
  1119.     uds = ads_getint(tbuf, &n);
  1120.     if (uds == RTCAN)
  1121.         return;
  1122.     else if (uds != RTNONE) {
  1123.         if (n > 1)
  1124.             for (uds = n; (uds & 1) == 0; uds >>= 1) ;
  1125.         else
  1126.             n = 2;
  1127.         if (uds != 1) {
  1128.             for (uds = 2; uds < n; uds <<= 1) ;
  1129.             n = uds;
  1130.         }
  1131.     }
  1132.  
  1133.     while (True) {
  1134.         int uds;
  1135.  
  1136.         ads_initget(2 + 4, NULL);
  1137.         V sprintf(tbuf, /*MSG17*/"\n\
  1138. Fractal dimension (typically between 1 and 3) <%g>: ",
  1139.                   fracdim);
  1140.         uds = ads_getreal(tbuf, &fracdim);
  1141.         if (uds == RTCAN)
  1142.             return;
  1143.         else if (uds == RTNONE)
  1144.             break;
  1145.         if (fracdim >= 0.0 && fracdim <= 4.0) {
  1146.             break;
  1147.         }
  1148.         ads_printf(/*MSG18*/"Fractal dimension must be between 0 and 4\n");
  1149.     }
  1150.  
  1151.     ads_initget(2, NULL);
  1152.     V sprintf(tbuf, /*MSG19*/"\nPower law scaling exponent <%g>: ", powscale);
  1153.     uds = ads_getreal(tbuf, &powscale);
  1154.     if (uds == RTCAN)
  1155.         return;
  1156.  
  1157.     initseed();
  1158.     if (forceseed) {
  1159.         initgauss(rseed);
  1160.         forceseed = False;
  1161.     }
  1162.  
  1163.     spectralsynth(&a, n, 3.0 - fracdim);
  1164.  
  1165.     /* Apply power law scaling if non-unity scale is requested. */
  1166.  
  1167.     if (powscale != 1.0) {
  1168.         for (i = 0; i < n; i++) {
  1169.             for (j = 0; j < n; j++) {
  1170.                 if (Real(a, i, j) > 0) {
  1171.                     Real(a, i, j) = pow((double) Real(a, i, j), powscale);
  1172.                 }
  1173.             }
  1174.         }
  1175.     }
  1176.  
  1177.     /* Compute extrema for autoscaling. */
  1178.  
  1179.     for (i = 0; i < n; i++) {
  1180.         for (j = 0; j < n; j++) {
  1181.             rmin = min(rmin, Real(a, i, j));
  1182.             rmax = max(rmax, Real(a, i, j));
  1183.         }
  1184.     }
  1185.  
  1186.     if (entmake)
  1187.         makemesh(a, n, rmax, rmin);
  1188.     else
  1189.         genmesh(a, n, rmax, rmin);
  1190.  
  1191.     free((char *) a);
  1192. }
  1193.  
  1194. /*  SEED  --  Set seed for random numbers.  */
  1195.  
  1196. static void seed()
  1197. {
  1198.     int uds;
  1199.     char tbuf[80], ibuf[134];
  1200.  
  1201.     initseed();
  1202.  
  1203.     V sprintf(tbuf, /*MSG20*/"Random number seed (0 to reseed) <0x%X>: ",
  1204.               rseed);
  1205.     uds = ads_getstring(False, tbuf, ibuf);
  1206.     if (uds == RTNORM) {
  1207.         if (strlen(ibuf))
  1208.             rseed = atoi(ibuf);
  1209.         if (rseed == 0) {
  1210.             seeded = False;
  1211.             initseed();
  1212.             ads_printf(/*MSG21*/"New seed is 0x%X.\n", rseed);
  1213.         }
  1214.         forceseed = True;
  1215.     }
  1216. }
  1217.  
  1218. /*  WORLD  --  Set world we're operating in.  */
  1219.  
  1220. static void world()
  1221. {
  1222.     int i;
  1223.     char tbuf[80];
  1224.  
  1225.     ads_textpage();
  1226.     ads_printf(/*MSG22*/"\nWorld:  0 = Landscape (8 colours)");
  1227.     ads_printf(/*MSG23*/"\n        1 = Landscape (256 colours)");
  1228.     ads_printf(/*MSG24*/"\n        2 = Clouds");
  1229.     V sprintf(tbuf, /*MSG25*/"\nWorld type <%d>: ", wtype);
  1230.     if (ads_getint(tbuf, &i) == RTNORM) {
  1231.         if (i < 0 || i > 2) {
  1232.             ads_printf(/*MSG26*/"Invalid world type.\n");
  1233.         } else {
  1234.             wtype = i;
  1235.         }
  1236.     }
  1237. }
  1238.  
  1239. /*  MAKEMODE  --  Set mesh generation method.  */
  1240.  
  1241. static void makemode()
  1242. {
  1243.     int i;
  1244.     char tbuf[80];
  1245.  
  1246.     ads_printf(
  1247.        /*MSG27*/"\nMesh generation:  0 = Directly with ads_entmake()");
  1248.     ads_printf(
  1249.        /*MSG28*/"\n                  1 = PFACE command via ads_command()");
  1250.     V sprintf(tbuf, /*MSG29*/"\nGeneration type <%d>: ", entmake ? 0 : 1);
  1251.     if (ads_getint(tbuf, &i) == RTNORM) {
  1252.         if (i < 0 || i > 1) {
  1253.             ads_printf(/*MSG30*/"Invalid mesh generation mode.\n");
  1254.         } else {
  1255.             entmake = i == 0 ? True : False;
  1256.         }
  1257.     }
  1258. }
  1259.  
  1260.  
  1261.  
  1262. #ifdef  HIGHC
  1263.  
  1264. /*  Early versions of High C put abort() in the same module with exit();
  1265.     RXADS defines its own exit(), so we have to define our own abort().  */
  1266.  
  1267. static void abort()
  1268. {
  1269.     ads_abort("");
  1270. }
  1271.  
  1272. #endif  /* HIGHC */
  1273.  
  1274.  
  1275. AcRx::AppRetCode
  1276. /*FCN*/acrxEntryPoint(AcRx::AppMsgCode msg, void * ptr)
  1277. {
  1278.  
  1279.     if (ptr != NULL) {
  1280.         // We have been handed some kind of object
  1281.         // but we aren't going to do anything with it.
  1282.     }
  1283.  
  1284.     switch(msg) {
  1285.         case AcRx::kInitAppMsg:
  1286.             break;
  1287.         case AcRx::kInvkSubrMsg:
  1288.             dofun();
  1289.             break;
  1290.         case AcRx::kLoadADSMsg:
  1291.             funcload();
  1292.             break;
  1293.         case AcRx::kUnloadADSMsg:
  1294.             funcunload();
  1295.             ads_printf(/*MSG2*/"Unloading.\n");
  1296.             break;
  1297.         case AcRx::kUnloadAppMsg:
  1298.         default:
  1299.             break;
  1300.     }
  1301.     return AcRx::kRetOK;
  1302. }
  1303.  
  1304.